﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ViewModel.cs" company="">
//   
// </copyright>
//  <summary>
//   The view model.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Shatranj
{
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;

    /// <summary>
    /// The view model.
    /// </summary>
    public abstract class ViewModel : INotifyPropertyChanged
    {
        // : DynamicModelBase
        #region Public Events

        /// <summary>
        /// The property changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The raise property changed.
        /// </summary>
        /// <param name="propertyName">
        /// The property name.
        /// </param>
        public void RaisePropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region Methods

        /// <summary>
        /// The on property changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            var handler = this.PropertyChanged;
            handler(sender, args);
        }

        #endregion
    }

    /// <summary>
    /// The dynamic object.
    /// </summary>
    public class DynamicObject
    {
    }

    /// <summary>
    /// The dynamic model base.
    /// </summary>
    public abstract class DynamicModelBase : DynamicObject, IDictionary<string, DynamicObject>, INotifyPropertyChanged
    {
        #region Fields

        /// <summary>
        /// The property bag.
        /// </summary>
        private readonly IDictionary<string, DynamicObject> propertyBag = new Dictionary<string, DynamicObject>();

        #endregion

        #region Public Events

        /// <summary>
        /// The property changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the count.
        /// </summary>
        public int Count
        {
            get
            {
                return this.propertyBag.Count;
            }
        }

        /// <summary>
        /// Gets a value indicating whether is read only.
        /// </summary>
        public bool IsReadOnly
        {
            get
            {
                return this.propertyBag.IsReadOnly;
            }
        }

        /// <summary>
        /// Gets the keys.
        /// </summary>
        public ICollection<string> Keys
        {
            get
            {
                return this.propertyBag.Keys;
            }
        }

        /// <summary>
        /// Gets the values.
        /// </summary>
        public ICollection<DynamicObject> Values
        {
            get
            {
                return this.propertyBag.Values;
            }
        }

        #endregion

        #region Public Indexers

        /// <summary>
        /// The this.
        /// </summary>
        /// <param name="key">
        /// The key.
        /// </param>
        /// <returns>
        /// The <see cref="DynamicObject"/>.
        /// </returns>
        public DynamicObject this[string key]
        {
            get
            {
                return this.propertyBag[key];
            }

            set
            {
                this.propertyBag[key] = value;
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The add.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        public void Add(KeyValuePair<string, DynamicObject> item)
        {
            this.propertyBag.Add(item);
        }

        /// <summary>
        /// The add.
        /// </summary>
        /// <param name="key">
        /// The key.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        public void Add(string key, DynamicObject value)
        {
            this.propertyBag.Add(key, value);
        }

        /// <summary>
        /// The clear.
        /// </summary>
        public void Clear()
        {
            this.propertyBag.Clear();
        }

        /// <summary>
        /// The contains.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool Contains(KeyValuePair<string, DynamicObject> item)
        {
            return this.propertyBag.Contains(item);
        }

        /// <summary>
        /// The contains key.
        /// </summary>
        /// <param name="key">
        /// The key.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool ContainsKey(string key)
        {
            return this.propertyBag.ContainsKey(key);
        }

        /// <summary>
        /// The copy to.
        /// </summary>
        /// <param name="array">
        /// The array.
        /// </param>
        /// <param name="arrayIndex">
        /// The array index.
        /// </param>
        public void CopyTo(KeyValuePair<string, DynamicObject>[] array, int arrayIndex)
        {
            this.propertyBag.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// The get enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        public IEnumerator<KeyValuePair<string, DynamicObject>> GetEnumerator()
        {
            return this.propertyBag.GetEnumerator();
        }

        /// <summary>
        /// The remove.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool Remove(KeyValuePair<string, DynamicObject> item)
        {
            return this.propertyBag.Remove(item);
        }

        /// <summary>
        /// The remove.
        /// </summary>
        /// <param name="key">
        /// The key.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool Remove(string key)
        {
            return this.propertyBag.Remove(key);
        }

        /// <summary>
        /// The try get value.
        /// </summary>
        /// <param name="key">
        /// The key.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool TryGetValue(string key, out DynamicObject value)
        {
            return this.propertyBag.TryGetValue(key, out value);
        }

        #endregion

        #region Explicit Interface Methods

        /// <summary>
        /// The get enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.propertyBag.GetEnumerator();
        }

        #endregion

        #region Methods

        /// <summary>
        /// The on property changed.
        /// </summary>
        /// <param name="propertyName">
        /// The property name.
        /// </param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;
            handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}